package asia.kalin.service.impl;

import asia.kalin.config.SnowflakeConfig;
import asia.kalin.domain.dto.AiResultDTO;
import asia.kalin.domain.po.DetectionResult;
import asia.kalin.domain.po.Dispose;
import asia.kalin.domain.po.PriceAssess;
import asia.kalin.domain.vo.DetectionResultOneVO;
import asia.kalin.domain.vo.DetectionResultVO;
import asia.kalin.enums.RedisKeyEnums;
import asia.kalin.mapper.DetectionResultMapper;
import asia.kalin.mapper.DisposeMapper;
import asia.kalin.mapper.PriceAssessMapper;
import asia.kalin.service.IDetectionResultService;
import asia.kalin.domain.ao.Result;
import asia.kalin.utils.ImageUtil;
import asia.kalin.utils.PromptUtil;
import asia.kalin.utils.DeepSeekJanusPro7B2Util;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhipu.oapi.service.v4.model.ModelApiResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author Kalin
 * @since 2025-03-10
 */
@Service
@RequiredArgsConstructor
public class DetectionResultServiceImpl extends ServiceImpl<DetectionResultMapper, DetectionResult> implements IDetectionResultService {

    private final StringRedisTemplate stringRedisTemplate;

    private final DisposeMapper disposeMapper;

    private final PriceAssessMapper priceAssessMapper;

    private static String UPLOAD_DIR = "/www/wwwroot/kalin.asia/ftp/";

    /**
     * 根据类型查询检测结果(未解决)
     * @param
     * @return
     */
    @Override
    public Result queryByTypeList() {
        // 拼接RedisKey
        String key = RedisKeyEnums.DETECTION_RESULT_TYPE_KEY;
        // 查询redis是否有
        String object = stringRedisTemplate.opsForValue().get(key);
        // 判断是否有值
        if(StrUtil.isNotBlank(object)){
            // 转换成PageNum返回
            List<DetectionResultVO> detectionResultVOList = JSONUtil.toList(object, DetectionResultVO.class);
            return new Result<>(0,"获取成功",detectionResultVOList);
        }

        // 没有值 查询数据库

        // 查询所有type类型且未解决的检测结果
        List<DetectionResultVO> detectionResultVOList = baseMapper.queryByTypeAndState();
        if(detectionResultVOList.isEmpty()){
            return new Result<>(1,"当前类型没有待解决问题",null);
        }

        // 转换成json字符串存入redis
        // 创建一个JSONConfig对象
        JSONConfig config = new JSONConfig();
        // 设置日期格式
        config.setDateFormat("yyyy-MM-dd HH:mm:ss");
        String jsonStr = JSONUtil.toJsonStr(detectionResultVOList,config);
        System.out.println(jsonStr);
        stringRedisTemplate.opsForValue().set(key,jsonStr,RedisKeyEnums.DETECTION_RESULT_TYPE_TTL, TimeUnit.HOURS);

        // 返回结果
        return new Result<>(0,"获取成功",detectionResultVOList);
    }

    /**
     * 根据ResultID查询检测结果详情
     * @param resultId
     * @return Result
     */
    @Override
    public Result queryByIdOne(String resultId) {
        // 拼接key
        String key = RedisKeyEnums.DETECTION_RESULT_ID_KEY + resultId;
        String object = stringRedisTemplate.opsForValue().get(key);
        // 判断是否有值
        if(StrUtil.isNotBlank(object)){
            // 转换json为VO类
            DetectionResultOneVO detectionResultOneVO = JSONUtil.toBean(object, DetectionResultOneVO.class);
            return new Result<>(0,"获取成功",detectionResultOneVO);
        }

        // 为空 查询数据库
        DetectionResult detectionResult = baseMapper.selectById(resultId);
        // 没有查到之间返回
        if(detectionResult == null){
            return new Result<>(1,"ID错误",null);
        }

        // 写入redis
        // 转换成json
        String jsonStr = JSONUtil.toJsonStr(detectionResult);
        stringRedisTemplate.opsForValue().set(key,jsonStr,RedisKeyEnums.DETECTION_RESULT_ID_TTL,TimeUnit.HOURS);

        // 转换成VO返回
        DetectionResultOneVO detectionResultOneVO = BeanUtil.toBean(detectionResult, DetectionResultOneVO.class);

        return new Result<>(0,"获取成功",detectionResultOneVO);
    }

    /**
     * 根据摄像头上传的图片进行检测分析 生成检测内容
     * @param file 用户上传的图片
     * @return Result
     */
    @Override
    @Transactional
    public Result generatesDetectionResultsByAI(MultipartFile file,String cameraId) {
        // 上传文件得到URL
        String url = uploadFile(file);
        if(url == null){
            return new Result<>(1,"上传失败",null);
        }
        // 图片转换成Base64
        String imgBase64 = ImageUtil.convertImageToBase64Str(UPLOAD_DIR + url);

        // 调用ai
        ModelApiResponse invokeModelApiResp = DeepSeekJanusPro7B2Util.generatesDetectionResultsByAI(PromptUtil.prompt, imgBase64);
        // deep-seek-janus-pro
        // String result = DeepSeekJanusPro7BUtil.multimodalUnderstanding(imgBase64);
        // 接收返回Json字符串
        String objectJson = String.valueOf(invokeModelApiResp.getData().getChoices().get(0).getMessage().getContent());
        // 处理json字符串
        int indexOf = objectJson.indexOf('`');
        if(indexOf != -1){
            objectJson = objectJson.substring(7, objectJson.length() - 3);
        }
        // 转换成AiResultDTO
        AiResultDTO aiResultDTO = JSONUtil.toBean(objectJson, AiResultDTO.class);
        // 插入数据库
        // 检测结果
        String resultId = String.valueOf(new SnowflakeConfig().snowflake().nextId());
        DetectionResult detectionResult = new DetectionResult(
                resultId,
                cameraId,
                aiResultDTO.getType(),
                "https://www.kalin.asia/ftp/" + url,
                aiResultDTO.getGrade(),
                aiResultDTO.getTitle(),
                aiResultDTO.getDescription(),
                aiResultDTO.getSolution(),
                LocalDateTime.now(),
                LocalDateTime.now()
        );
        int insert1 = baseMapper.insert(detectionResult);
        if(insert1 <= 0){
            return new Result<>(1,"识别失败",null);
        }
        // 结果处理
        String disposeId = String.valueOf(new SnowflakeConfig().snowflake().nextId());
        Dispose dispose = new Dispose();
        dispose.setDisposeId(disposeId);
        dispose.setResultId(resultId);
        dispose.setState(0);
        dispose.setUpdateTime(LocalDateTime.now());
        dispose.setCreateTime(LocalDateTime.now());
        int insert2 = disposeMapper.insert(dispose);
        if(insert2 <= 0){
            return new Result<>(1,"识别失败",null);
        }
        // 价格评估
        String assessId = String.valueOf(new SnowflakeConfig().snowflake().nextId());
        PriceAssess priceAssess = new PriceAssess();
        priceAssess.setAssessId(assessId);
        priceAssess.setResultId(resultId);
        priceAssess.setPrice(aiResultDTO.getPrice());
        priceAssess.setProjectDescription(aiResultDTO.getProjectDescription());
        priceAssess.setUpdateTime(LocalDateTime.now());
        priceAssess.setCreateTime(LocalDateTime.now());
        int insert3 = priceAssessMapper.insert(priceAssess);
        if(insert3 <= 0){
            return new Result<>(1,"识别失败",null);
        }
        return new Result<>(0,"识别成功",objectJson);
    }

    /**
     * 上传图片
     * @param file 图片
     * @return 图片地址
     */
    public String uploadFile(MultipartFile file){
        try {
            // 生成一个唯一的文件名
            String originalFilename = file.getOriginalFilename();
            String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
            String randomFilename = UUID.randomUUID() + fileExtension;

            // 构建上传文件的完整路径
            Path destinationFile = Paths.get(UPLOAD_DIR).resolve(randomFilename).toAbsolutePath();

            // 保存文件
            Files.copy(file.getInputStream(), destinationFile);

            return randomFilename;
        } catch (IOException e) {
            return null;
        }
    }
}
